/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package arbol_sintactico_abstracto;

import analizadorlexico.Token;
import generador_de_codigo.GeneradorDeCodigo;
import java.io.IOException;
import java.util.List;
import tabla_de_simbolos.Clase;
import tabla_de_simbolos.Constructor;
import tabla_de_simbolos.ErrorSemantico;
import tabla_de_simbolos.Metodo;
import tabla_de_simbolos.ModificadorMetodo;
import tabla_de_simbolos.TablaDeSimbolos;
import tabla_de_simbolos.Tipo;

/**
 *
 * @author Javi
 */
public class Llamada {
    private Token id;
    private List<Expresion> args;

    public Llamada(Token id, List<Expresion> args) {
        this.id = id;
        this.args = args;
    }

    public Token getId() {
        return id;
    }

    public List<Expresion> getArgs() {
        return args;
    }    
    
    /**
     * 
     * @param clase: clase en donde se encuentra la llamada
     * @param metodo: metodo en el que se hace la llamada
     * @param t_id: tipo del objeto al que se le realiza la llamada
     * @return tipo de retorno de la llamada
     * @throws ErrorSemantico 
     */
    public Tipo check(Clase clase, Constructor metodo, Tipo t_id,ModificadorMetodo mod, TablaDeSimbolos ts) throws ErrorSemantico, IOException{
        Metodo actual = null;
        
        if(t_id.esPrimitivo())
            throw new ErrorSemantico("No se puede realizar llamada sobre un tipo primitivo. Linea: "+ id.getLinea());
        actual = ((Clase)t_id).getTablaMetodos().get(id.getLexema());
        
        if(actual == null)
            throw new ErrorSemantico("Metodo "+id.getLexema()+" no definido. Linea: " + id.getLinea());
        
        if(!actual.getModMetodo().getModificador().equals(mod.getModificador())){
            throw new ErrorSemantico("Se esperaba un metodo "+ mod.getModificador() +" en la linea "+ id.getLinea());
        }
        
        if(actual.getParametros().size() != args.size())
            throw new ErrorSemantico("La cantidad de argumentos no coinciden. Linea: " + id.getLinea());
       
        if(!actual.getTipoRetorno().getNombre().equals("void")){
            GeneradorDeCodigo.generar("RMEM 1 \n");    //Reservo un lugar para el valor de retorno
            if(mod.getModificador().equals("dynamic"))
                GeneradorDeCodigo.generar("SWAP \n");
        }
        
        for(int i = 0 ; i < args.size() ; i ++){
            if(!args.get(i).check(clase, metodo,ts).conforma(actual.getParametros().get(i).getTipo()))
                throw new ErrorSemantico("Paramentros incompatibles en la linea "+ id.getLinea());
            if(mod.getModificador().equals("dynamic"))
                GeneradorDeCodigo.generar("SWAP \n");
        }
        
        if(mod.getModificador().equals("dynamic")){
            GeneradorDeCodigo.generar("DUP \n");
            GeneradorDeCodigo.generar("LOADREF 0 \n");
            GeneradorDeCodigo.generar("LOADREF "+ (actual.getOffset() - 1) + "\n");
            GeneradorDeCodigo.generar("CALL \n");
        }
        else{
            GeneradorDeCodigo.generar("PUSH " + t_id.getNombre() + "_" + actual.getNombre() + "\n");
            GeneradorDeCodigo.generar("CALL \n");
        }
        return actual.getTipoRetorno();
    }
    
}
